package com.runa.rccprotocol.analysis;

import com.alibaba.fastjson.JSON;
import com.runa.monitor.comm.dto.newComm.AffiliatePanelVO;
import com.runa.monitor.comm.dto.newComm.HotMeterVO;
import com.runa.monitor.comm.dto.newComm.ValveVO;
import com.runa.persistence.util.LogUtil;
import com.runa.protocol.analysis.ShellBufferAnalysis;
import com.runa.protocol.dto.DtuReport;
import com.runa.protocol.dto.IInterData;
import com.runa.protocol.enums.ByteOrder;
import com.runa.protocol.util.ByteUtil;
import com.runa.protocol.util.UtilTime;
import com.runa.rccprotocol.dto.runa.RunaConcenAffirmDeny;
import com.runa.rccprotocol.dto.runa.RunaConcenResponseData;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ApportionCollectorAnalysis extends ShellBufferAnalysis<byte[]> {

    public ApportionCollectorAnalysis() {
        super(null, 128);
    }

    @Override
    public int fill(byte[] data, int length, String netEquNo) {
        log.debug("正定: {} {}", netEquNo, ByteUtil.byteToHexString(data, 0, length));
        this.interData = null;
        if (length == 1 && this.netEquNo != null) {
            this.interData = new DtuReport(this.netEquNo);
            LogUtil.linkDetect(this.netEquNo, "正定", data, length, "心跳");
        } else if (length >= 28 && "CHITIC".equals(new String(data, 0, 6))) {
            this.netEquNo = new String(data, 6, 9).trim();
            LogUtil.linkDetect(this.netEquNo, "正定", data, length, "登录");
            String sim = new String(data, 15, 11);
            this.interData = new DtuReport(this.netEquNo);
            return length - 28;
        } else if (data[0] == 0x68) {
            if (length < 20) return -1;
            int len = ByteUtil.byteToUShort(data, 1, ByteOrder.BA);
            if (length < 8 + len) return -1;
            if (ByteUtil.sum(data, 6, len) == data[6 + len]) {
                byte c = data[6];
                if (c == 0x41) {
                    byte afn = data[12];
                    byte seq = data[13];
                    int dt = ByteUtil.byteToUShort(data, 16, ByteOrder.AB);
                    if (afn == 0x0c) {
                        RunaConcenResponseData responseData = new RunaConcenResponseData();
                        if (dt == 0x4003) {
                            responseData.addRepData(hotMeter(data, 22));
                        } else if (dt == 0x2003) {
                            responseData.addRepData(valveData(data, 22));
                        }
                        responseData.setUpward(true);
                        this.interData = responseData;
                    } else if (afn == 0 && dt == 0x400) {
                        String vid = ByteUtil.byteToHexStringFlip(data, 23, 5);
                        this.interData = new RunaConcenAffirmDeny(data[28] == 0);
                    } else if (afn == 0x55) {//透传数据
                        if (data[22] == (byte) 0x46 && data[30] == (byte) 0x81) {
                            RunaConcenResponseData responseData = new RunaConcenResponseData();
                            //校验
                            byte check = data[length - 2];
                            if (check != ByteUtil.sum(data, 6, length - 8)) {
                                return 0;
                            }
                            responseData.addRepData(houseValveData(data, 23));
                            this.interData = responseData;
                        } else if (data[22] == (byte) 0x68 && data[23] == (byte) 0x20) {
                            RunaConcenResponseData responseData = new RunaConcenResponseData();
                            byte check = data[length - 2];
                            if (check != ByteUtil.sum(data, 6, length - 8)) {
                                return 0;
                            }
                            RunaDeviceAnalysis runaDeviceAnalysis = new RunaDeviceAnalysis();
                            responseData.addRepData(runaDeviceAnalysis.heatMeterData(24, data));
                            this.interData = responseData;
                        } else if (data[30] == (byte) 0x84) {//写返回
                            interData = new RunaConcenAffirmDeny(this.netEquNo, true);
                        } else if (length > 25 && data[16] == 0x01 && data[17] == 0x00) {
                            int index = 18;
                            while (data[index] == (byte) 0xfe) {
                                if (index > length) {
                                    return 0;
                                }
                                index++;
                            }
                            if (data[index] == (byte)0x68) {
                                log.debug("正定188: {} {}", netEquNo, ByteUtil.byteToHexString(data, 0, length));
                                if ((data[index+1] == (byte)0x25 || data[index+1] == (byte) 0x20)) {
                                    if (data[index+1+8] == (byte)0x81) {
                                        RunaConcenResponseData responseData = new RunaConcenResponseData();
                                        byte check = data[length - 2];
                                        if (check != ByteUtil.sum(data, 6, length - 8)) {
                                            log.debug("校验和比较失败: {} {}", check, ByteUtil.sum(data, 6, length - 8));
                                            return 0;
                                        }
                                        RunaDeviceAnalysis runaDeviceAnalysis = new RunaDeviceAnalysis();
                                        responseData.setAddress(netEquNo);
                                        responseData.addRepData(runaDeviceAnalysis.heatMeterData(netEquNo, data, index+2));
                                        this.interData = responseData;
                                    }
                                }
                            } else {
                                log.debug("正定modbus: {} {}", netEquNo, ByteUtil.byteToHexString(data, 0, length));
                                int slaveId = data[index++];
                                int functionCode = data[index++];
                                int dateByteSize = data[index++];
                                if (functionCode == 4 && dateByteSize == 72) {
                                    HotMeterVO meterVO = new HotMeterVO();
                                    meterVO.setMeterSerial("0000000000000"+slaveId);
                                    meterVO.setFlow(ByteUtil.byteToFloat(data, index, ByteOrder.CDAB));
                                    index += 16;
                                    int accFlowInt = ByteUtil.byteToInt(data, index, ByteOrder.CDAB);
                                    index += 4;
                                    float accFlowDec = (float) (ByteUtil.byteToInt(data, index, ByteOrder.CDAB) * 0.001);
                                    index += 4;
                                    meterVO.setAccFlow(accFlowInt+accFlowDec);
                                    index += 16;
                                    meterVO.setPower(ByteUtil.byteToFloat(data, index, ByteOrder.CDAB));
                                    index += 4;
                                    meterVO.setSupplyTemp(ByteUtil.byteToFloat(data, index, ByteOrder.CDAB));
                                    index += 4;
                                    meterVO.setReturnTemp(ByteUtil.byteToFloat(data, index, ByteOrder.CDAB));
                                    index += 4;
                                    int accHeatInt = ByteUtil.byteToInt(data, index, ByteOrder.CDAB);
                                    index += 4;
                                    float accHeatDec = (float) (ByteUtil.byteToInt(data, index, ByteOrder.CDAB) * 0.001);
                                    index += 4;
                                    meterVO.setAccHeat(accHeatInt+accHeatDec);
                                    index += 8;
                                    short powerUnit = ByteUtil.byteToShort(data, index, ByteOrder.BA);
                                    index += 2;
                                    short heatUnit = ByteUtil.byteToShort(data, index, ByteOrder.BA);
                                    switch (powerUnit) {
                                        case 0:
                                            break;
                                        case 1:
                                            meterVO.setPower(meterVO.getPower() * 1000);
                                            break;
                                        case 2:
                                            meterVO.setPower(meterVO.getPower() / 3600);
                                            break;
                                        case 3:
                                            meterVO.setPower((float) (meterVO.getPower() / 3.6));
                                            break;
                                        case 4:
                                            meterVO.setPower((float) (meterVO.getPower() / 0.0036));
                                            break;
                                    }
                                    switch (heatUnit) {
                                        case 0:
                                            break;
                                        case 1:
                                            meterVO.setAccHeat(meterVO.getAccHeat() * 1000);
                                            break;
                                        case 2:
                                            meterVO.setAccHeat(meterVO.getAccHeat() / 3600);
                                            break;
                                        case 3:
                                            meterVO.setAccHeat((float) (meterVO.getAccHeat() / 3.6));
                                            break;
                                        case 4:
                                            meterVO.setAccHeat((float) (meterVO.getAccHeat() / 0.0036));
                                            break;
                                    }
                                    RunaConcenResponseData responseData = new RunaConcenResponseData();
                                    responseData.addRepData(meterVO);
                                    interData = responseData;
                                }
                            }
                        }

                    }
                }
            }
        }
        return 0;
    }

    @SneakyThrows
    private Object houseValveData(byte[] data, int index) {
        ValveVO valveVO = new ValveVO();
        valveVO.setValveSerial(ByteUtil.bcd2str(data, index, 7, false));
        valveVO.setTemperatureLockTarget((float) (Float.valueOf(ByteUtil.bcd2str(data, index + 12, 2, false)) * 0.01));
        valveVO.setEnvTemp((float) (Float.valueOf(ByteUtil.bcd2str(data, index + 14, 2, false)) * 0.01));

        valveVO.setSupplyTemp((float) (Float.valueOf(ByteUtil.bcd2str(data, index + 18, 2, false)) * 0.01));
        valveVO.setReturnTemp((float) (Float.valueOf(ByteUtil.bcd2str(data, index + 20, 2, false)) * 0.01));
        valveVO.setOpenTime((float) (Float.valueOf(ByteUtil.bcd2str(data, index + 26, 4, false)) * 0.01));//分钟
        valveVO.setActOpen((float) (Integer.parseInt(ByteUtil.bcd2str(data, index + 38, 1, false), 16)));
        valveVO.setValveDate(UtilTime.StringToDate(ByteUtil.bcd2str(data, index + 39, 7, false), "yyyyMMddHHmmss"));
        valveVO.setStatus(ByteUtil.bcd2str(data, index + 46, 2, false));
        int statusCode = Integer.parseInt(valveVO.getStatus(), 16);
        valveVO.setOpenLock((statusCode >> 14 & 1) == 1);

        AffiliatePanelVO panel = new AffiliatePanelVO(0, 0, valveVO.getEnvTemp(), (short) 0);
        panel.setReadTime(valveVO.getReadTime());
        panel.setSerial(valveVO.getValveSerial());
        if ((statusCode >> 6 & 1) == 1 || (statusCode >> 7 & 1) == 1) {
            panel.setSuccess(false);
        }
        valveVO.getPanelVOList().add(panel);
        return valveVO;
    }

    private HotMeterVO hotMeter(byte[] data, int index) {
        HotMeterVO meterVO = new HotMeterVO();
        meterVO.setReadDate(UtilTime.StringToDate(ByteUtil.byteToHexString(data, index, 5), "mmHHddMMyy"));
        meterVO.setMeterSerial(ByteUtil.byteToHexStringFlip(data, index + 5, 5));
        meterVO.setSupplyTemp(ByteUtil.byteToFloat(data, index + 10, ByteOrder.DCBA));
        meterVO.setReturnTemp(ByteUtil.byteToFloat(data, index + 14, ByteOrder.DCBA));
        meterVO.setPower(ByteUtil.byteToFloat(data, index + 18, ByteOrder.DCBA));
        meterVO.setWorkTime(ByteUtil.byteToFloat(data, index + 22, ByteOrder.DCBA).intValue());
        meterVO.setFlow(ByteUtil.byteToFloat(data, index + 26, ByteOrder.DCBA));
        meterVO.setAccFlow(ByteUtil.byteToFloat(data, index + 30, ByteOrder.DCBA));
        meterVO.setAccHeat(ByteUtil.byteToFloat(data, index + 34, ByteOrder.DCBA));
        meterVO.setStatus(ByteUtil.byteToHexString(data, index + 40, 4));
        return meterVO;
    }

    private ValveVO valveData(byte[] data, int index) {
        ValveVO valveVO = new ValveVO();
        valveVO.setReadTime(UtilTime.StringToDate(ByteUtil.byteToHexString(data, index, 5), "mmHHddMMyy"));
        valveVO.setValveSerial(ByteUtil.byteToHexStringFlip(data, index + 5, 5));
        valveVO.setSupplyTemp(ByteUtil.byteToFloat(data, index + 10, ByteOrder.DCBA));
        valveVO.setReturnTemp(ByteUtil.byteToFloat(data, index + 14, ByteOrder.DCBA));
//        float setTemp = ByteUtil.byteToFloat(data, index+18, ByteOrder.DCBA);
        valveVO.setEnvTemp(ByteUtil.byteToFloat(data, index + 22, ByteOrder.DCBA));
        valveVO.setOpenTime(ByteUtil.byteToFloat(data, index + 26, ByteOrder.DCBA));
        float factor = (float) (ByteUtil.byteToUShort(data, index + 38, ByteOrder.BA) * 0.01);
        valveVO.setStatus(ByteUtil.byteToHexString(data, index + 66, 4));
        valveVO.setActOpen((float) data[index + 74]);
        double setTemp = ByteUtil.bcdToInt(data, index + 75, 2, false) * 0.01;
        switch (data[index + 81]) {
            case 0x55:
                valveVO.setModel(ValveVO.ModelEnum.室温);
                break;
            case 0x66:
                valveVO.setModel(ValveVO.ModelEnum.供回温差);
                break;
            case 0x77:
                valveVO.setModel(ValveVO.ModelEnum.回温);
        }
        valveVO.setRemoteSet((float) data[index + 82]);
        return valveVO;
    }

    public static void main(String[] args) {
        ApportionCollectorAnalysis analysis = new ApportionCollectorAnalysis();
//        byte[] bytes = ByteUtil.hexStringToByte("68 63 00 63 00 68 41 02 37 01 00 02 0C E0 00 00 20 03 58 02 00 00 10 13 27 11 23 03 00 24 12 21 33 33 DF 41 9A 99 E1 41 00 00 F0 41 00 00 02 42 66 66 DA 41 C4 2C 00 00 00 00 00 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 00 80 BF 00 00 20 00 01 01 00 66 64 78 16");
        //上线
//        byte[] bytes = ByteUtil.hexStringToByte("43 48 49 54 49 43 32 30 32 31 31 32 32 34 31 31 35 30 36 37 32 32 37 38 30 33 0D 0A");
        //阀数据
//        byte[] bytes = ByteUtil.hexStringToByte("68 43 00 43 00 68 41 02 37 01 00 00 55 E0 00 00 01 00 FE FE FE 68 46 88 10 24 10 00 00 21 81 27 90 1F 01 00 18 00 18 78 18 90 24 90 24 45 83 04 00 41 16 01 00 51 27 00 00 00 00 00 00 06 39 17 17 07 12 23 20 41 80 41 16 43 16 ");
//        byte[] bytes = ByteUtil.hexStringToByte("68430043006841023701000055E000000100FEFEFE6846100006170000008127901F010000902290224120422064942400547924000000000008345678143349111412232041833F163F16");
//        byte[] bytes = ByteUtil.hexStringToByte("684B004B006841023701000055E000000100FEFEFEFE682032811105005555812E1F90018526090005022869090528580000171636130035148028022C2435004631005093023450131701242000007116A116  ");
        //阀
        byte[] bytes = ByteUtil.hexStringToByte("68430043006841023701000055E000000100FEFEFE6846910724100000218127901F0100230020202010231022646851001788050048480100420000000313121129031720434C9A16F516");
        analysis.fill(bytes, bytes.length, null);
        IInterData gain = analysis.gain();
        System.out.println(JSON.toJSONString(gain));
    }

}
